#include "nodetopology.h"
#include <QVariant>
#include <QDebug>

NodeTopology::NodeTopology(QObject *parent, unsigned int TestDuration,
                           unsigned int boundaryValue, unsigned int spaceTime):
    QObject(parent),
    m_TestDuration(TestDuration),
    m_boundaryValue(boundaryValue),
    m_spaceTime(spaceTime),
    m_Testcounter(0)
{
    connect(&m_testTime,SIGNAL(timeout()),this,SLOT(slt_cyclicTestNet()));
    connect(&m_controlTimer,SIGNAL(timeout()),this,SLOT(slt_testNet()));
    connect(this,SIGNAL(sig_nodeChange(Node)),this,SLOT(slt_testRouter(Node)));
}
void NodeTopology::slt_addAnode(const Node &n)
{
    map_nodes.insert(n.getName(),n);
}
void NodeTopology::slt_modifyTestDuration(unsigned int t)
{
    m_TestDuration = t;
}
void NodeTopology::slt_cyclicTestNet()//轮转测试
{
    allNodeAddSelfByOne();//所有节点权指加1
    QNodeMap::iterator ite = map_nodes.begin();
    while (ite != map_nodes.end()) {
        if ( ite.value().getState() && ite.value().getM_weight() >= m_boundaryValue) {
            m_testTime.stop();//关闭循环测试定时器
            sig_TestNode(ite.value().getCMD(TEST));
            m_currentTestNode = ite.value();
            m_currentTestNode.isVaild = true;
            m_controlTimer.start(m_spaceTime);//打开选定节点的测试定时器
            break;
        }
        qDebug() << ite.value().getName() << ite.value().getM_weight();
        ++ite;
    }

    qDebug() << trUtf8("轮转测试");

}
/**
 * @brief NodeTopology::slt_testNet 存在问题，bug严重，需要理论支持，理论系统研究
 */
void NodeTopology::slt_testNet()//节点丢失测试
{
    ++m_Testcounter;
    if (m_Testcounter > 3) {//三次判断为丢失
        QNodeMap::iterator ite = map_nodes.find(m_currentTestNode.getName());
        m_controlTimer.stop();
        m_Testcounter = 0;
        ite.value().makeLost();//标识节点丢失
        m_currentTestNode.isVaild = false;

        (*ite).makeLost();
        (*ite).m_weightClear0();

        emit sig_nodeChange((*ite).getDescription(),
                            (*ite).getAddress(),
                            (*ite).getParentAd(),
                            (*ite).getName(),false);

        qDebug() << (*ite).getName() <<trUtf8("丢失");

        emit sig_realTimeInfo(trUtf8("网络丢失-->设备名:%1").arg((*ite).getName()));

        QString con = trUtf8("设备丢失,设备名:%1 描述:%2").arg((*ite).getName())
                .arg(DBcontrol::selectDevDes((*ite).getName()));
        Message me(Parameters::cmsaddr,Parameters::phone,con);
        emit sig_Message(me);
        m_testTime.start(m_TestDuration);
    }
    else {
        sig_TestNode(m_currentTestNode.getCMD(TEST));//发送给串口
        qDebug() << trUtf8("节点丢失测试");
    }



}
void NodeTopology::slt_NodeInfo(const QString &/*address*/)//只接受拓扑的反馈和添加信息
{

}
void NodeTopology::allNodeAddSelfByOne()
{
    QNodeMap::iterator ite = map_nodes.begin();
    while (ite != map_nodes.end()) {
        if ((*ite).getDescription() != Coordinator && (*ite).getState()) {
            (*ite).m_weightAddSelfByOne();
        }
        ++ite;
    }

}
void NodeTopology::slt_buildNet(const QString &/*value*/)
{
}

void NodeTopology::slt_NodeTest(const QString &addr, ushort name)
{
    if (m_currentTestNode.isVaild && m_currentTestNode.getAddress() == addr
            && map_nodes.contains(name)) {
        QNodeMap::iterator i = map_nodes.find(name);
        m_controlTimer.stop();
        i.value().m_weightClear0();
        m_testTime.start(m_TestDuration);
        m_Testcounter = 0;
    }
}
void NodeTopology::slt_buildNet(char type, const QString &addr,
                                const QString &parentAddr, ushort name)
{
    //离开网络又加入网络
    if (type == 'C') {
        map_nodes.clear();
        r_map.clear();
        slt_stopTest(); // 完成一系列的清除工作
    }
    if (map_nodes.contains(name)) { //这个节点已经在网络中
        //得到这个节点
        Node &i = map_nodes.find(name).value();//得到这个节点
        if (m_currentTestNode.getName() == i.getName()) { //如果真在测试这个节点不用测试了
            restartTest();
        }
        Node &pn = getParent(i.getParentAd());//得到原来父亲节点
        //父节点
        if (pn.getAddress() == parentAddr) {//父节点地址不变
            i.makeNotLost(); //丢失标示位设置为不丢失
        } else {
            //父节点改变
            i.setAddress(addr);
            i.setParentAd(parentAddr);
            i.makeNotLost();
            emit sig_nodeChange(i.getDescription(),i.getAddress(),i.getParentAd(),i.getName(),true);
        }
        if (pn.getDescription() == Router) {
            /*
                     *路由节点重新加入且不再原来的位置，则原来位置的子节点必须变化
                     *
                     */
            removeADEformRouter(pn.getName(),name);
            Node &npn = getParent(parentAddr);//得到现在父亲的节点
            if (npn.getDescription() == Router) {
                // insertIntoRouter(npn.getName(),name);

            }
            if (npn.getDescription() == Coordinator) {
                // insertIntoCood(name);
            }

        }
        if (pn.getDescription() == Coordinator) {

        }


    } else {
        //新节点
        Node n;
        n.setAddress(addr);
        n.setParentAd(parentAddr);
        n.setName(name);
        n.setDevDescription(DBcontrol::selectDevDes(name));

        if (type == 'E') {
            n.setDescription(EndDevice);

            Node &pn = getParent(parentAddr);
            if (pn.getDescription() == Router) {
                insertIntoRouter(pn.getName(),name);
            } else {
                if (pn.getDescription() == Coordinator) {
                    insertIntoCood(name);
                }
            }

        } else {
            if (type == 'R') {
                n.setDescription(Router);
                r_map.insert(name,QNodeList());

                Node &pn = getParent(parentAddr);
                if (pn.getDescription() == Router) {
                    insertIntoRouter(pn.getName(),name);
                } else {
                    if (pn.getDescription() == Coordinator) {
                        insertIntoCood(name);
                    }
                }
            } else {
                n.setDescription(Coordinator);
                n.setAddress(addr);
                n.setParentAd("");
                m_testTime.start(m_TestDuration);
            }
        }

        map_nodes.insert(name,n);
        n.makeNotLost();
        emit sig_newNode(n);
    }

}
void NodeTopology::slt_badData(ushort name, int flag, int value)
{
    //根据name得到节点
    QNodeMap::iterator i = map_nodes.find(name);
    if (i.value().hasFlag(flag)) {
        Value &v = i.value().getValue(flag);
        //现在的值与保存的值相差大于规定的值,发送这个值和更新
        if ((qAbs(v.m_lastValue - value) > Parameters::interval)
                || (v.m_lastTime.secsTo(QTime::currentTime()) / 60 > Parameters::interval_time)) {
            v.m_lastValue = value;
            v.m_lastTime = QTime::currentTime();
            //发送
            doBadValue(flag,value,i.value().getDevDescription());
            DBcontrol::insertBadValue(QStringList() << QString::number(name) << QDate::currentDate().toString("yyyy-MM-dd")
                                      << QTime::currentTime().toString("hh:mm:ss") << Node::getFlagInfo(flag)
                                      << QString::number(value) << i.value().getDevDescription());

        }
    } else {
        //添加在发送
        Value newV;
        newV.m_falg = flag;
        newV.m_lastValue = value;
        newV.m_lastTime = QTime::currentTime();
        i.value().addValue(newV);
        doBadValue(flag,value,i.value().getDevDescription());
        DBcontrol::insertBadValue(QStringList() << QString::number(name) << QDate::currentDate().toString("yyyy-MM-dd")
                                  << QTime::currentTime().toString("hh:mm:ss") << Node::getFlagInfo(flag)
                                  << QString::number(value) << i.value().getDevDescription());


    }
}

bool NodeTopology::aRouterIsLost(const Node &RouterNode) const
{
    QMap<ushort,QNodeList>::const_iterator i = r_map.find(RouterNode.getName());
    if (i != r_map.end()) {
        foreach (ushort name, i.value()) {
            QNodeMap::const_iterator i2 = map_nodes.find(name);
            if (i2.value().getState()) {
                return false;
            }

        }
    }
    return true;
}
bool NodeTopology::aCoordinatorIsLost() const
{
    foreach (ushort name, c_list) {
        QNodeMap::const_iterator i2 = map_nodes.find(name);
        if (i2.value().getState()) {
            return false;
        }
    }
    return true;
}
/**
 * @brief NodeTopology::getParent 根据地址得到节点
 * @param parentAdd 节点地址，是一个节点的父节点地址
 * @return
 */
Node& NodeTopology::getParent(const QString &parentAdd)
{

    qDebug() << parentAdd;

    QList<Node> nlist = map_nodes.values();
    QNodeMap::iterator ite;
    foreach (const Node &n, nlist) {
        if (n.getAddress() == parentAdd) {
            ite = map_nodes.find(n.getName());
            break;
        }
    }
    return (*ite);
}
void NodeTopology::removeADEformRouter(ushort pname, ushort name)
{
    QMap<ushort,QNodeList>::iterator ite = r_map.find(pname);
    ite.value().removeOne(name);


}
void NodeTopology::removeFormCood(ushort name)
{
    c_list.removeOne(name);

}

void NodeTopology::insertIntoRouter(ushort pname, ushort name)
{
    QMap<ushort,QNodeList>::iterator ite = r_map.find(pname);
    ite.value().append(name);

}
void NodeTopology::insertIntoCood(ushort name)
{
    c_list.append(name);
}
Node& NodeTopology::getNodeByName(ushort name)
{
    QNodeMap::iterator ite = map_nodes.find(name);
    return ite.value();
}
void NodeTopology::testRouterOrCood(const Node &n)
{
    sig_TestNode(n.getCMD(TEST));
    m_currentTestNode = n;
    m_currentTestNode.isVaild = true;
    m_testTime.stop();
    m_controlTimer.start(m_spaceTime);
}
void NodeTopology::slt_stopTest()
{
    m_testTime.stop();
    m_controlTimer.stop();
    map_nodes.clear();
    c_list.clear();
    r_map.clear();

}
void NodeTopology::slt_nodeClear0(ushort name)
{
    Node &n = getNodeByName(name);
    if (!m_currentTestNode.isVaild) {
        n.m_weightClear0();
    } else {
        if (m_currentTestNode.getName() == name) {
            n.m_weightClear0();
            restartTest();

        }
    }


}

Node& NodeTopology::getCood()
{
    QList<Node> nlist = map_nodes.values();
    QNodeMap::iterator ite;
    foreach (const Node &n, nlist) {
        if (n.getDescription() == Coordinator) {
            ite = map_nodes.find(n.getName());
            break;
        }
    }
    return (*ite);

}
void NodeTopology::clearARouter(ushort name)
{
    QMap<ushort,QNodeList>::iterator ite = r_map.find(name);
    ite.value().clear();
}

void NodeTopology::doBadValue(int flag, int value, const QString &des)
{
    QString con = QObject::trUtf8("%1异常 值:%2 描述:%3").arg(Node::getFlagInfo(flag),
                                                         QString::number(value),des);
    Message me(Parameters::cmsaddr,Parameters::phone,con);
    emit sig_Message(me);
    emit sig_realTimeInfo(trUtf8("发送信息-->内容:%1 接受号码:%2").arg(con,Parameters::phone));
}

void NodeTopology::restartTest()
{
    m_controlTimer.stop();
    m_testTime.start(m_TestDuration);

    m_currentTestNode.isVaild = false;
    m_Testcounter = 0;

}
void NodeTopology::slt_testRouter(const Node &n)
{
    if (n.getDescription() == EndDevice || n.getDescription() == Coordinator) {

    } else {
        Node &pn = getParent(n.getParentAd());
        if (aRouterIsLost(pn)) {
            pn.setState(false);
            emit sig_nodeChange(pn);
            testRouterOrCood(pn);
        }
    }
}

#ifdef TEST_NET

void NodeTopology::test()
{
    //'E',"0005","0004",'F'
    Node n;
    n.setName('F');
    n.setState(false);
    n.setParentAd("0004");
    n.setAddress("0005");
    n.setDescription(EndDevice);

    emit sig_nodeChange(n);

}

#endif


void NodeTopology::slt_get_cmd(ushort dev_name, quint8 _cmd)
{
    Node &n = getNodeByName(dev_name);
    //
    emit sig_control_cmd(n.getCMD(_cmd));
}

